package com.link.base.base.approval.service;

import com.link.base.base.approval.dao.mybatis.mapper.ApprovalOperateMapper;
import com.link.base.base.approval.model.ApprovalOperate;
import com.link.base.base.approval.model.Flow;
import com.link.base.base.approval.model.OtherFlowInfo;
import com.link.core.cllog.LCLogger;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.ServiceException;
import com.link.core.util.BeanTools;
import com.link.core.util.StringUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * Copyright  hande Company. All Rights Reserved.
 *
 * @author  unknwon
 * @date:   2018/11/8 14:40
 * @version 1.0
 */

@Service
public class ApprovalOperateServiceImpl extends BasicServiceImpl<ApprovalOperate> implements ApprovalOperateService {

    private static final Pattern PATTERN = Pattern.compile("(?<=\\[)([^\\(^\\)]+?)(?=\\])");

    @Resource
    private ApprovalOperateMapper approvalOperateMapper;

    public static void main(String[] args) {
        try {
            System.out.println(Class.forName("com.link.base.order.service.OrderService"));
        } catch (ClassNotFoundException e) {
            LCLogger.withException(e);
        }

    }

    @Override
    public BasicMapper<ApprovalOperate> getBasicMapper() {
        return approvalOperateMapper;
    }

    /**
     * 执行审核回调函数
     * @param flow
     * @param operateId
     * @param nextNodeSn
     * @throws Exception
     */
    @Override
    @SuppressWarnings("rawtypes")
    public void doOperateService(Flow flow, Long operateId, String nextNodeSn) throws Exception {
        Long objectId = flow.getFlowObjId();
        if (objectId == null) {
            throw new ServiceException("APPROVAL-003");
        }
        ApprovalOperate example = new ApprovalOperate();
        example.setId(operateId);
        ApprovalOperate record = queryById(example);
        if (record == null) {
            throw new ServiceException("APPROVAL-004",operateId.toString());
        }
        String objectPath =  record.getObjectPath() == null ? "" : record.getObjectPath().trim();
        String methodName = record.getMethodName() == null ? "" : record.getMethodName().trim();
        String needNextNode = record.getNeedNextNode() == null ? "" : record.getNeedNextNode().trim();
        String flag = "Y";
        if (StringUtils.isBlank(objectPath)) {
            throw new ServiceException("APPROVAL-005",operateId.toString());
        }
        if (StringUtils.isBlank(methodName)) {
            throw new ServiceException("APPROVAL-006",operateId.toString());
        }
        if (StringUtils.isBlank(needNextNode) && flag.equals(needNextNode)) {
            if (!StringUtils.isBlank(nextNodeSn)) {
                //必须无后续节点设为“Y”，但存在审批的后续流程时。不调用回调函数
                return;
            }
        }
        Object bean = null;
        Method med = null;
        try {
            Class<?> object = Class.forName(objectPath);
            bean = BeanTools.getBean(object);
            Class[] param = new Class[6];
            param[0] = Flow.class;
            param[1] = String.class;
            param[2] = String.class;
            param[3] = String.class;
            param[4] = String.class;
            param[5] = String.class;
            med = bean.getClass().getMethod(methodName, param);
            String param1 = record.getParam1();
            String param2 = record.getParam2();
            String param3 = record.getParam3();
            String param4 = record.getParam4();
            String param5 = record.getParam5();
            med.invoke(bean, flow, param1, param2, param3, param4, param5);
        } catch (InvocationTargetException e) {
            LCLogger.withException(e);
            Exception ex = (Exception) e.getTargetException();
            throw new ServiceException("APPROVAL-007",ex.getMessage());
        } catch (ClassNotFoundException cfe) {
            LCLogger.withException(cfe);
            throw new ServiceException("APPROVAL-008");
        } catch (Exception e) {
            LCLogger.withException(e);
            throw new ServiceException("APPROVAL-009");
        }
    }

    /**
     * 执行其他操作
     * @param objectId
     * @param operateId
     * @param otherInfo
     * @throws Exception
     */
    @Override
    public void doOtherOperate(Long objectId, Long operateId, OtherFlowInfo otherInfo) throws Exception {
        if (objectId == null) {
            throw new ServiceException("APPROVAL-003");
        }
        ApprovalOperate example = new ApprovalOperate();
        example.setId(operateId);
        ApprovalOperate record = queryById(example);
        if (record == null) {
            throw new ServiceException("APPROVAL-004",operateId.toString());
        }
        String objectPath =  record.getObjectPath() == null ? "" : record.getObjectPath().trim();
        String methodName = record.getMethodName() == null ? "" : record.getMethodName().trim();
        if (StringUtils.isBlank(objectPath)) {
            throw new ServiceException("APPROVAL-005",operateId.toString());
        }
        if (StringUtils.isBlank(methodName)) {
            throw new ServiceException("APPROVAL-006",operateId.toString());
        }
        Object bean = null;
        Method med = null;
        try {
            Class<?> object = Class.forName(objectPath);
            bean = BeanTools.getBean(object);
            @SuppressWarnings("rawtypes")
            Class[] param = new Class[11];
            param[0] = String.class;
            param[1] = String.class;
            param[2] = String.class;
            param[3] = String.class;
            param[4] = String.class;
            param[5] = String.class;
            param[6] = String.class;
            param[7] = String.class;
            param[8] = String.class;
            param[9] = String.class;
            param[10] = String.class;
            med = bean.getClass().getMethod(methodName, param);
            med.invoke(bean, objectId, otherInfo.getAttr1(), otherInfo.getAttr2(), otherInfo.getAttr3(),
                    otherInfo.getAttr4(), otherInfo.getAttr5(), otherInfo.getAttr6(), otherInfo.getAttr7(),
                    otherInfo.getAttr8(), otherInfo.getAttr9(), otherInfo.getAttr10());
        } catch (InvocationTargetException e) {
            LCLogger.withException(e);
            Exception ex = (Exception) e.getTargetException();
            throw new ServiceException("APPROVAL-007",ex.getMessage());
        } catch (ClassNotFoundException cfe) {
            LCLogger.withException(cfe);
            throw new ServiceException("APPROVAL-008");
        } catch (Exception e) {
            LCLogger.withException(e);
            throw new ServiceException("APPROVAL-009");
        }
    }

    /**
     *  获取下一操作节点序号
     * 如果有判断条件，先根据判断条件进行处理
     * @param objectId
     * @param operateId
     * @return String
     * @throws Exception
     */
    @Override
    public String getDecideWithNextNodeNo(Long objectId, Long operateId) throws Exception {
        if (null == objectId) {
            throw new ServiceException("APPROVAL-003");
        }
        if (null == operateId) {
            return null;
        }
        ApprovalOperate example = new ApprovalOperate();
        example.setId(operateId);
        ApprovalOperate record = queryById(example);
        if (record == null) {
            throw new ServiceException("APPROVAL-004",operateId.toString());
        }
        String objectPath =  record.getObjectPath() == null ? "" : record.getObjectPath().trim();
        String methodName = record.getMethodName() == null ? "" : record.getMethodName().trim();
        if (StringUtils.isBlank(objectPath)) {
            throw new ServiceException("APPROVAL-005",operateId.toString());
        }
        if (StringUtils.isBlank(methodName)) {
            throw new ServiceException("APPROVAL-006",operateId.toString());
        }
        Object bean = null;
        Method med = null;
        try {
            Class<?> object = Class.forName(objectPath);
            bean = BeanTools.getBean(object);
            @SuppressWarnings("rawtypes")
            Class[] param = new Class[1];
            param[0] = Long.class;
            med = bean.getClass().getMethod(methodName, param);
            Object objectValue = med.invoke(bean, objectId);
            String decideExpression = record.getDecideExpression();

            Matcher match = PATTERN.matcher(decideExpression);
            List<String> filedList = new ArrayList<String>();
            while (match.find()) {
                filedList.add(match.group());
            }
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("js");
            for (int i = 0; filedList != null && i < filedList.size(); i++) {
                String field = filedList.get(i);
                Object colData = null;
                try {
                    colData = PropertyUtils.getSimpleProperty(objectValue, field);
                } catch (Exception e) {
                    LCLogger.withException(e);
                }
                decideExpression = decideExpression.replaceAll("\\[" + field + "\\]", "\\$" + field + "\\$");
                engine.put("$" + field + "$", colData);
            }
            Object nodeNo = engine.eval(decideExpression);
            return String.valueOf(nodeNo);
        } catch (InvocationTargetException e) {
            LCLogger.withException(e);
            Exception ex = (Exception) e.getTargetException();
            throw new ServiceException("APPROVAL-010" ,ex.getMessage());
        } catch (ClassNotFoundException cfe) {
            LCLogger.withException(cfe);
            throw new ServiceException("APPROVAL-008");
        }  catch (Exception e) {
            LCLogger.withException(e);
            throw new ServiceException("APPROVAL-010" ,e.getMessage());
        }
    }

}
